{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# `auto` 与模板参数推导的差异\n",
    "\n",
    "- `auto` 推导遵循“模板实参推导”规则，但其语法位置固定在变量声明上，不涉及模板形参列表。\n",
    "- `auto` 变量不可显式指定类别（如 `auto x<int>` 不允许），而函数模板可通过显式实参指定。\n",
    "- `auto` 推导保留引用/const 规则与模板形参一致，但在解包等场景受限。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "#include <iostream>\n",
    "#include <type_traits>\n",
    "\n",
    "template <typename T>\n",
    "void func(T value) {\n",
    "    std::cout << std::boolalpha\n",
    "              << \"T is const? \" << std::is_const_v<T> << '\\n';\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "T is const? false\n",
      "x is const? false\n",
      "rx is const? true\n"
     ]
    }
   ],
   "source": [
    "{\n",
    "    const int ci = 42;\n",
    "    auto x = ci;          // x 推导为 int（顶层 const 被丢弃）\n",
    "    func(ci);             // T 推导为 int（同样丢弃顶层 const）\n",
    "    auto& rx = ci;        // 引用语义需显式 &\n",
    "\n",
    "    std::cout << \"x is const? \" << std::is_const_v<decltype(x)> << '\\n';\n",
    "    std::cout << \"rx is const? \" << std::is_const_v<std::remove_reference_t<decltype(rx)>> << '\\n';\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> `auto` 推导遵循“模板实参推导”规则，但其语法位置固定在变量声明上，不涉及模板形参列表。:\n",
    "\n",
    "这句话想表达的是：\n",
    "\n",
    "- 当你在变量声明里写 `auto x = expr;` 时，编译器用的推导规则与模板实参推导（template argument deduction）相同：也就是“根据初始化表达式推断出类型，再生成对应的具体类型”。比如 `auto x = 3.14;` 推导结果类似于模板参数 `T` 根据 `3.14` 被推成 `double` 的那个逻辑，规则一致。\n",
    "- 但 `auto` 只能写在变量声明（或函数返回类型、lambda 形参等特定语法位置）中，不能像模板那样出现在模板形参列表里进行“正式”的类型参数声明。因此它虽然借用了模板实参推导的规则，却不需要也不能声明成 `template<typename T>` 那样的模板，只是在局部使用模板推导的那套算法来确定类型。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# `typename` vs `class` & 依赖名解析\n",
    "\n",
    "- 在模板参数列表中，`typename` 与 `class` 等效（`template<typename T>` == `template<class T>`）。\n",
    "- 在模板内部指涉依赖类型（dependent name）时需使用 `typename` 告诉编译器它是类型而非静态成员/值。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "#include <iostream>\n",
    "\n",
    "template <typename T>\n",
    "struct Wrapper {\n",
    "    using value_type = typename T::value_type; // 依赖名需 typename\n",
    "    value_type data;\n",
    "};\n",
    "\n",
    "struct Sample {\n",
    "    using value_type = int;\n",
    "};"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10\n"
     ]
    }
   ],
   "source": [
    "{\n",
    "    Wrapper<Sample> w{10};\n",
    "    std::cout << w.data << '\\n';\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 折叠表达式（fold expression）与参数包求和\n",
    "\n",
    "- 折叠表达式将参数包按运算符折叠，如 `(args + ...)`。\n",
    "- C++17 支持一元左折叠、右折叠和带初值的折叠。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "#include <iostream>\n",
    "\n",
    "template <typename... Args>\n",
    "auto sum(Args... args) {\n",
    "    return (args + ... + 0); // 右折叠带初值\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10\n"
     ]
    }
   ],
   "source": [
    "{\n",
    "    std::cout << sum(1, 2, 3, 4) << '\\n';\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# `if constexpr` 的作用与与 `#if` 区别\n",
    "\n",
    "- `if constexpr` 在编译期判定条件，未选择的分支不会实例化（可避免错误）。\n",
    "- `#if` 是预处理器指令，作用于代码文本；`if constexpr` 是编译期语义层面的条件。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "#include <iostream>\n",
    "#include <type_traits>\n",
    "\n",
    "template <typename T>\n",
    "void print_info(const T& value) {\n",
    "    if constexpr (std::is_integral_v<T>) {\n",
    "        std::cout << value << \" is integral\\n\";\n",
    "    } else {\n",
    "        std::cout << value << \" is not integral\\n\";\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "42 is integral\n",
      "3.14 is not integral\n"
     ]
    }
   ],
   "source": [
    "{\n",
    "    print_info(42);\n",
    "    print_info(3.14);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 模板实例化顺序引发的 SFINAE\n",
    "\n",
    "- SFINAE（Substitution Failure Is Not An Error）：在模板实参替换期间若出现不合法表达式，该模板被排除而非报错。\n",
    "- 利用 SFINAE 可根据表达式合法性选择重载。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "#include <iostream>\n",
    "#include <type_traits>\n",
    "\n",
    "template <typename T>\n",
    "auto test(int) -> decltype(std::declval<T>().size(), std::true_type{});\n",
    "\n",
    "template <typename>\n",
    "std::false_type test(...);\n",
    "\n",
    "template <typename T>\n",
    "void print_size(const T& obj) {\n",
    "    if constexpr (decltype(test<T>(0))::value) {\n",
    "        std::cout << \"size = \" << obj.size() << '\\n';\n",
    "    } else {\n",
    "        std::cout << \"no size()\\n\";\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "size = 5\n",
      "no size()\n"
     ]
    }
   ],
   "source": [
    "{\n",
    "    print_size(std::string{\"hello\"});\n",
    "    print_size(42);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# `std::enable_if_t` 约束重载\n",
    "\n",
    "- `std::enable_if_t<condition, T>` 在条件为真时产出类型 `T`，否则替换失败，帮助限定模板重载可用性。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "#include <iostream>\n",
    "#include <type_traits>\n",
    "\n",
    "template <typename T,\n",
    "          std::enable_if_t<std::is_integral_v<T>, int> = 0>\n",
    "void process(T value) {\n",
    "    std::cout << \"integral: \" << value << '\\n';\n",
    "}\n",
    "\n",
    "template <typename T,\n",
    "          std::enable_if_t<std::is_floating_point_v<T>, int> = 0>\n",
    "void process(T value) {\n",
    "    std::cout << \"floating: \" << value << '\\n';\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "integral: 10\n",
      "floating: 3.14\n"
     ]
    }
   ],
   "source": [
    "{\n",
    "    process(10);\n",
    "    process(3.14);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# CRTP（Curiously Recurring Template Pattern）\n",
    "\n",
    "- 子类将自身作为模板实参传给基类，让基类使用静态多态（编译期绑定“虚函数”）。\n",
    "- 常用于静态接口约束、mixins、政策类等。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "#include <iostream>\n",
    "\n",
    "template <typename Derived>\n",
    "struct Base {\n",
    "    void interface() {\n",
    "        static_cast<Derived*>(this)->implementation();\n",
    "    }\n",
    "};\n",
    "\n",
    "struct Derived : Base<Derived> {\n",
    "    void implementation() { std::cout << \"Derived implementation\\n\"; }\n",
    "};"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Derived implementation\n"
     ]
    }
   ],
   "source": [
    "{\n",
    "    Derived d;\n",
    "    d.interface(); // 调用 Derived::implementation\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# `template<auto N>` vs 传统整型非类型模板参数\n",
    "\n",
    "- `template<auto N>` 允许任意可作为非类型模板参数的类型（整型、指针、枚举等），无需指定具体类型。\n",
    "- 传统写法如 `template<int N>` 仅限指定类型。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "#include <iostream>\n",
    "\n",
    "template <auto N>\n",
    "void print_value() {\n",
    "    std::cout << N << '\\n';\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "42\n",
      "A\n",
      "0x79cde9d5602c\n"
     ]
    }
   ],
   "source": [
    "{\n",
    "    print_value<42>();\n",
    "    print_value<'A'>();\n",
    "    static int x = 5;\n",
    "    print_value<&x>();\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# C++17 聚合类型规则变化\n",
    "\n",
    "- 以前要求“无继承、无非静态成员初始化器”等；C++17 放宽条件：\n",
    "  - 允许具有 `private/protected` 成员但只要没有用户提供或继承的构造函数即可（仍需公共成员可聚合初始化）。\n",
    "  - 允许带有括号内成员初始值（如 `int x = 0;`）仍被视为聚合。\n",
    "- 不再是聚合的条件：存在用户自定义构造函数、虚函数、虚基类、私有或受保护的非静态成员、基类为非聚合等（符合标准最新条款）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Aggregate is aggregate: true\n",
      "NonAggregate is aggregate: false\n",
      "10, 20\n"
     ]
    }
   ],
   "source": [
    "#include <iostream>\n",
    "#include <type_traits>\n",
    "\n",
    "struct Aggregate {\n",
    "    int x = 1;   // C++17 起仍算聚合\n",
    "    int y;\n",
    "};\n",
    "\n",
    "struct NonAggregate {\n",
    "    NonAggregate() {} // 用户提供构造 -> 非聚合\n",
    "    int x;\n",
    "};\n",
    "\n",
    "{\n",
    "    std::cout << std::boolalpha\n",
    "              << \"Aggregate is aggregate: \"\n",
    "              << std::is_aggregate_v<Aggregate> << '\\n'\n",
    "              << \"NonAggregate is aggregate: \"\n",
    "              << std::is_aggregate_v<NonAggregate> << '\\n';\n",
    "\n",
    "    Aggregate a{10, 20}; // 聚合初始化\n",
    "    std::cout << a.x << \", \" << a.y << '\\n';\n",
    "}"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++17",
   "language": "C++17",
   "name": "xcpp17"
  },
  "language_info": {
   "codemirror_mode": "text/x-c++src",
   "file_extension": ".cpp",
   "mimetype": "text/x-c++src",
   "name": "c++",
   "version": "17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
